<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>生命周期（新）</title>
</head>
<body>
  <div id="root"></div>
  <script src="../js/react.development.js"></script>
  <script src="../js/react-dom.development.js"></script>
  <script src="../js/babel.min.js"></script>
  <script type="text/babel">
    class Demo extends React.Component {
      /**
        组件初始化时被调用，
        作用：
          1. 初始化 state，
          2. 为事件函数绑定组件实例
        注意点：
          1. 不能调用 setState 来更新状态，如果使用状态，则可直接对 state 进行初始化
          2. 再使用 this 之前必须先调用 super(props)
          3. 避免将 props 的值赋值给 state

        如果再调用 super 时不传入 props，则在之后使用 this.props 可能为 null
      */
      constructor(props) {
        super(props)
        console.log('Demo---constructor')

        this.state = {
          count: 0,
          stateOther: 'stateOther'
        }
      }

      /**
        在 render 方法调用之前调用；在组件初始挂载及后续更新时都会被调用
        应返回一个对象或者 null，返回 null 时则不更新任何内容

        返回值：必须是一个对象或者 null，不能为 undefined

        作用：返回值将做为 state；

        场景：state 的值在任何情况都取决于 props；一般情况下，当 props 变化时来修改 state 才会使用此方法
      */
      static getDerivedStateFromProps(props, state) {
        console.log('Demo---getDerivedStateFromProps', props, state)
        // 1. 返回为 null，则该是什么样还是什么样，不更新任何内容
        return null
        // 2. 返回一个对象，且将这个对象合并到 state 中
        // return {
        //   // count: props.count,
        //   count: props.other
        // }
      }

      /**
        组件挂载后
        一般用于：
          1. 网络请求
          2. 订阅信息，（在 componentWillUnmount 即将卸载时取消订阅）
      */
      componentDidMount() {
        console.log('Demo---componentDidMount')
      }

      /**
        组件是否应该更新必须返回 true/false。如果返回 true，则可更新；如果返回 false，则不更新
      */
      shouldComponentUpdate(a, b, c) {
        console.log('Demo---shouldComponentUpdate', a, b, c)
        return true
      }

      /**
        在最近一次渲染输出（提交到 DOM 节点）之前调用
        它使得组件能在发生更改之前从 DOM 中捕获一些信息（滚动位置）；此生命周期的任何返回值将做为参数传递给 `componentDidUpdate()`
      */
      getSnapshotBeforeUpdate(prevProps, prevState) {
        console.log('Demo---getSnapshotBeforeUpdate', prevProps, prevState)
        return null
      }

      /**
        组件更新之后被触发
      */
      componentDidUpdate(prevProps, prevState, snapShot) {
        console.log('Demo---componentDidUpdate', prevProps, prevState, snapShot)
      }

      /**
        组件将要卸载时触发，一般用来做一些取消订阅，取消定时器等善后的操作
      */
      componentWillUnmount() {
        console.log('Demo---componentWillUnmount')
      }

      handleClick = () => {
        this.setState({
          count: this.state.count+1
        })
      }

      render() {
        console.log('Demo---render')
        return (
          <div>
            当前 count 的值为 { this.state.count }
            <button onClick={this.handleClick}>count+1</button>
          </div>
        )
      }
    }
    ReactDOM.render(<Demo count={123} other={456} />, document.getElementById('root'))
  </script>


  <style>
    ul {
      padding: 0;
      list-style: none;
    }
    .container {
      height: 150px;
      width: 200px;
      border: 1px solid #bbb;
      background-color: skyblue;
      overflow: auto;
    }
    .container .item {
      height: 30px;
      line-height: 30px;
      border: 1px solid #eee;
      box-sizing: border-box;
    }
  </style>
  <div id="root1" style="border-top: 2px solid #aaa; margin: 50px 0 20px;"></div>
  <script type="text/babel">
    class Scroll extends React.Component {

      state = {
        list: []
      }

      containerRef = React.createRef()

      componentDidMount() {
        this.intervalId = setInterval(() => {
          const { list } = this.state
          list.unshift({ id: list.length+1, value: `item${list.length+1}` })
          this.setState({
            list
          })
        }, 1000);
      }

      getSnapshotBeforeUpdate(prevProps, prevState) {
        console.log('getSnapshotBeforeUpdate: ', prevProps, prevState, this.containerRef)
        return this.containerRef.current.scrollHeight
      }

      componentDidUpdate(prevProps, prevState, snapshot) {
        console.log('componentDidUpdate: ', prevProps, prevState, snapshot, this.containerRef.current.scrollHeight)
        this.containerRef.current.scrollTop = this.containerRef.current.scrollTop + this.containerRef.current.scrollHeight - snapshot
      }

      componentWillUnmount() {
        clearInterval(this.intervalId)
      }

      render() {
        return (
          <ul className="container" ref={this.containerRef}>
            {
              this.state.list.map((item, index) => <li className="item" key={index}>{item.value}</li>)
            }
          </ul>
        )
      }
    }

    class List extends React.Component {

      state = {
          newsArr: []
      }
      listRef = React.createRef();

      componentDidMount() {
          this.timer = setInterval(() => {
              let {newsArr} = this.state;
              let news = '新闻' + (newsArr.length + 1);
              newsArr.unshift(news);
              this.setState({
                  newsArr
              });
          }, 1000);
      }

      // getSnapshotBeforeUpdate(preProps, preState) {
      //     console.log('getSnapshotBeforeUpdate: ',this.listRef, this.listRef.current.scrollHeight, preProps, preState);
      //     // return null;
      //     return this.listRef.current.scrollHeight;
      // }

      // componentDidUpdate(preProps, preState, snapshot) {
      //     console.log('snpashot: ', snapshot);
      //     this.listRef.current.scrollTop += this.listRef.current.scrollHeight - snapshot;
      // }

      componentWillUnmount(preProps, preState, snapshot) {
          clearInterval(this.timer);
      }

      render() {
          return (
              <ul className="container" ref={this.listRef}>
                  {
                      this.state.newsArr.map((n, index) => {
                        return <li className="item" key={index}>{n}</li>  
                      })
                  }
              </ul>
          );
      }
      }

    ReactDOM.render(<Scroll />, document.getElementById('root1'))
  </script>
</body>
</html>